﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Imagiality.MeshProcessing
{
    public abstract class SceneQuery<T> where T:SceneObject
    {
        private SceneQuery<T> innerQuery;
        private int depthLimit;

        public SceneQuery(SceneQuery<T> innerQuery, int depthLimit)
        {
            this.innerQuery = innerQuery;
            this.depthLimit = depthLimit;
        }

        public SceneQuery(int depthLimit) : this(null,depthLimit)
        {
        
        }

        public SceneQuery(SceneQuery<T> innerQuery) : this(innerQuery, 0)
        { 
           
        }

        public SceneQuery() : this(null,0)
        { 
            
        }

        public IList<T> Execute(IList<SceneObject> sceneObjects)
        {
            IList<SceneObject> toBeQueried = sceneObjects;
            if(innerQuery != null)
            {
                toBeQueried = (IList<SceneObject>)innerQuery.Execute(toBeQueried);
            }

            return DoExecute(0, toBeQueried);
        }

        protected virtual IList<T> DoExecute(int level, IList<SceneObject> sceneObjects)
        {
            IList<T> results = new List<T>();
      
            foreach(SceneObject obj in sceneObjects)
            {
                if (IsMatch(obj))
                {
                    results.Add((T)obj);        
                }

                if (obj.GetChilds() != null && obj.GetChilds().Count > 0)
                {
                    if (ProcessNextLevel(level + 1, obj))
                    {
                        if (depthLimit == 0 || level + 1 < depthLimit)
                        {
                                IList<SceneObject> res = (IList<SceneObject>)obj.GetChilds().ToArray();
                                results = results.Union(DoExecute(level + 1, res)).ToList();
                        }
                    }
                }
            }

            return results;
        }

        protected abstract bool IsMatch(SceneObject obj);
        protected abstract bool ProcessNextLevel(int level, SceneObject parent);
    }





}
